﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using IrisGenerator.Common.UI.Controls;

using System.Reflection;

using System.Collections;
using System.Drawing;
using IrisGenerator.Common.Tools;
using IrisGenerator.Framework.UI.Controls;
using IrisGenerator.Framework.Reflection;
using IrisGenerator.Framework.Messaging;

namespace IrisGenerator.Common.Core.UI
{
    public class ListBase<T>:ExtendedListView,IBindableControl
    {

        #region Fields

        /// <summary>
        /// Flag that notifies wether data was already loaded when the control is created
        /// </summary>
        private bool _calledOnLoad;

        //private IList _dataSource;

        #endregion

        #region Properties

        /// <summary>
        /// Defines the method that will be used as the data source of the grid.
        /// </summary>
        public MethodCall SourceMethod { get; set; }

        /// <summary>
        /// Implementation of the IBaseControl interface.
        /// </summary>
        /// <remarks>
        /// The property defines the kind of object the grid will bind to.
        /// The LoadSource method will attempt to create an instance of the type passing
        /// the result of the SourceMethod call as a parameter to the constructor.
        /// </remarks>
        public string BindingType { get; set; }

        #endregion

        /// <summary>
        /// Overriden to make a call to the LoadSource method on the control creation.
        /// </summary>
        protected override void OnCreateControl()
        {
            
            base.OnCreateControl();
            if (!_calledOnLoad)
            {
                this._calledOnLoad = true;
                this.LoadSource();
            }
        }

        #region Message Handling

        /// <summary>
        /// If the base object of the data source implements the IrisGenerator.Common.Core.Messaging.IMessageSender`1 interface
        /// the MessageSend event will be handled in the MessageReceived method.
        /// </summary>
        protected virtual void SetMessageHandler()
        {
            
            if (this.DataSource == null)
                return;
            Type interf = this.DataSource.GetType().GetInterface("IrisGenerator.Common.Core.Messaging.IMessageSender`1");
            if (interf != null)
            {
                IMessageSender<T> obj = this.DataSource as IMessageSender<T>;
                if (obj != null)
                    obj.MessageSend += new EventHandler<MessageEventArgs<T>>(MessageReceived);
            }
        }

        /// <summary>
        /// Handles MessageSend events fired from the objects in the datasource
        /// </summary>
        /// <remarks>
        /// Makes a call to the MessageToMessageBox.Show method passing the message in the event argument.
        /// </remarks>
        /// <param name="sender">The object that fired the message.</param>
        /// <param name="e">The message argument that was sent.</param>
        protected virtual void MessageReceived(object sender, MessageEventArgs<T> e)
        {
            if (e != null)
            {
                e.Message.Result = MessageToMessageBox.Show(e.Message);
            }
        }

        #endregion

        #region Source loading

        /// <summary>
        /// Loads the data source of the grid.
        /// </summary>
        /// <remarks>
        /// If a SourceMethod object is defined, the method is invoked. If a Binding type is defined, then
        /// the source is changed to this type. The method tries to call the constructor of the BindigType
        /// passing it the result of the previous method call as a parameter.
        /// </remarks>
        public virtual void LoadSource()
        {
            object targetSource = null;

            if (this.SourceMethod != null && !this.DesignMode)
            {
                object methodCallResult = GetDataSourceFromMethod();
                if (methodCallResult != null)
                {
                    ConstructorInfo ctor = GetBindingTypeConstructor(methodCallResult);

                    if (ctor != null)
                    {
                        object[] parameters = new object[1] { methodCallResult };
                        targetSource = ctor.Invoke(parameters);
                    }
                    else
                    {
                        targetSource = methodCallResult;
                    }
                }
                else
                    targetSource = null;
            }

            this.DataSource = targetSource as IList;
            RefreshUI();
            SetMessageHandler();
        }

        private ConstructorInfo GetBindingTypeConstructor(object methodCallResult)
        {
            ConstructorInfo ctor = null;
            if (!string.IsNullOrEmpty(this.BindingType))
            {
                Type destinationType = Type.GetType(this.BindingType);
                if (destinationType != null)
                {

                    if (destinationType.IsGenericTypeDefinition)
                    {
                        Type o = destinationType.MakeGenericType(new Type[1] { typeof(T) });
                        ctor = o.GetConstructor(new Type[1] { typeof(IList<T>) });
                    }
                    else
                    {
                        Type[] parameters = new Type[1];
                        parameters[0] = methodCallResult.GetType();
                        ctor = destinationType.GetConstructor(parameters);
                    }
                }
            }
            return ctor;
        }

        /// <summary>
        /// Invokes the method defined in the SourceMethod Property
        /// </summary>
        /// <returns></returns>
        private object GetDataSourceFromMethod()
        {
            bool result;
            object tmp = SourceMethod.Invoke(this, out result);
            return tmp;
        }

        private void RefreshUI()
        {
            this.Items.Clear();
            this.CreateColumns();
            this.CreateGroups();
            this.AddItems();
           
            //foreach (object obj in this._dataSource)
            //{
            //    for (int i=0;i<this.Columns.Count;i++)
            //    {
            //        if (this.Columns[i].Tag!=null)
            //        {
            //            object value = ReflectionTools.GetPropertyValue(obj, Convert.ToString(this.Columns[i].Tag));
            //            this.Items.Add(Convert.ToString(value));
            //        }
            //    }
            //}
            //if (this.ListColumns.Count > 0 && this._dataSource != null)
            //{
            //    bool itemSet=false;
            //    foreach (object obj in this._dataSource)
            //    {
            //        ListViewItem item = null;

            //        for (int i = 0; i < this.Items.Count; i++)
            //        {
            //            object value=GetPropertyValue(obj, this.ListColumns[i].Tag);
                        
            //            if (!itemSet && this.ListColumns[i].Visible)
            //            {
            //                item = this.Items.Add(Convert.ToString(value));
            //                item.ImageIndex = this.ListColumns[i].ImageIndex;
            //                itemSet = true;
            //            }
            //            else if (itemSet && this.ListColumns[i].Visible)
            //                item.SubItems.Add(Convert.ToString(value));
            //        }
            //    }
            //}
        }

        private void CreateColumns()
        {
            
        }

        private void CreateGroups()
        {
        }

        private void AddItems()
        {
            if (this.DataSource == null || this.Template == null || 
                this.Template.ItemTemplate == null)
                return;

            int i = 0;
            IList source = this.DataSource as IList;
            if (source != null)
            {
                foreach (object obj in source)
                {
                    if (i % 2 == 0 || this.Template.AlternateItemTemplate==null)
                    {
                        ListItem li = new ListItem();
                        this.Items.Add(li);
                        ListTemplate.LoadItem(li, this.Template.ItemTemplate, obj);
                    }
                    else
                    {
                        ListItem li = new ListItem();
                        this.Items.Add(li);
                        ListTemplate.LoadItem(li, this.Template.AlternateItemTemplate, obj);
                    }
                    i++;
                }
            }

        }

        //private void LoadGroupName(ListTemplate.ListItemTemplate template)
        //{
        //    if (!string.IsNullOrEmpty(this.Template.ItemTemplate.GroupName))
        //    {
        //        foreach (ListViewGroup lvg in this.Groups)
        //        {
        //            if (lvg.Name.Equals(this.Template.ItemTemplate.GroupName))
        //            {
        //                li.Group = lvg;
        //                break;
        //            }
        //        }
        //    }
        //}

        
        
        #endregion

    }
}
